test(driver-sql): budget the 35 inline live-DDL it() blocks across 8 files - #14098
Merged
Merged
Conversation
Thirty-five it() blocks nested in a declareDialectCell(...) callback across eight files each construct a FRESH new SqlDriver(...) against the cell's live MySQL/Postgres server inside their own body, so every one pays a full live connect cycle -- and for all but the charset probe, schema-sync DDL and an information_schema read-back -- per test rather than once in a beforeAll. None carried an explicit timeout, so all inherited vitest's own 5000ms default; the package sets no testTimeout, so that really is vitest's number and not a chosen one. Give each an explicit 60_000 budget, matching e4dc299, with one rationale comment per file naming why and disclaiming that it asserts anything about how slow these tests normally are. Deliberately NOT touched: the five in-cell it() blocks whose live work is hoisted into a beforeAll (sql-driver-backend-fault-envelope.test.ts x2, sql-driver-diagnostic-value-probe.test.ts x3) -- a different cost model, and the latter file's beforeAll is already budgeted at 60_000. No production code, no assertion, and no control changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 1, 2026
zhuangjianguo
marked this pull request as ready for review
September 1, 2026 05:54
zhuangjianguo
enabled auto-merge
September 1, 2026 05:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13902
The defect
Thirty-five
it(...)blocks nested in adeclareDialectCell(...)callback, across eightfiles in
packages/drivers/driver-sql, each construct a freshnew SqlDriver(...)against the cell's live MySQL/Postgres server inside their own body. Every one of them
therefore pays a full live connect cycle per test — and, for all but one charset probe,
schema-sync DDL plus an
information_schemaread-back on top of it — rather than sharing adriver opened once in a
beforeAll.None carried an explicit timeout, so all inherited vitest's own 5000ms default. That is not
a chosen budget:
packages/drivers/driver-sql/vitest.config.tssets notestTimeout(re-readon this tree, not taken on faith), so the 5000ms really is vitest's number and nobody in this
repo picked it for live connect/DDL work.
What this is, and what it is not. This is a structural sweep — "does an explicit budget
exist" — not a list of observed CI failures. There is no live MySQL/PG in this environment,
so none of these 35 blocks executed here (proved below). The evidence that the shape is a real
defect is #13688: one measured instance, whose failures were timeouts rather than assertion
failures, with no MySQL error in the logs, on a diff that touched no driver. These 35 are not
35 observations of a timeout, and this PR does not claim they are.
The fix
Each of the 35 gets an explicit
60_000budget, matching the value chosen for this exactshape in commit
e4dc299a(PR #13908), plus one rationale comment per file that names why thebudget exists and — copying that precedent's disclaimer — states it is not an assertion
that these tests are normally anywhere near that slow.
60_000is not re-decided here. Measured on this tree, the package carries 9 explicit numericbudgets:
60_000x7,40_000x1,120_000x1. The40_000outlier issql-driver-connect-bound.test.ts,whose budget is load-bearing for a duration assertion (
elapsed > 8_000and< 20_000) — adifferent purpose entirely.
Scoping: per-
it(), not per-file, and not per-packageit(). A whole-fileit(count over the package is 1682; the population this PRtouches is the 35 that are both inside a
declareDialectCell(...)callback and open theirown driver. The rest are fast unit tests that should inherit the 5000ms default.
from. It is not grounds to re-budget a whole file.
packages/spec) really wassolved with a package-level
testTimeout, but the two test populations differ:packages/spec's are homogeneous, whiledriver-sqlmixes fast unit tests with live-DDLtests. A package-level budget here would silently re-time the 2000-plus tests that
legitimately want the fast default. Same shape, different solution — please do not "fix"
this back toward a package-level
testTimeout.Deliberately not touched
Five
it()blocks that are inside a dialect cell and unbudgeted, but whose live work ishoisted into a
beforeAll— a different cost model:sql-driver-backend-fault-envelope.test.ts:360,:379)beforeAllat:160/:343builds the driver; theit()s issue 1-2 queries against the already-open connectionsql-driver-diagnostic-value-probe.test.ts:366,:385,:431)it()s reading aMappopulated inbeforeAll; they touch no server at allThe second file is also the repo's own answer for this shape: its
beforeAllalready carries}, 60_000)at:335. Budgeting the hook, not theit(), is what the reuse shape wants.A2.1 — re-run the triage sweep on the current tree, with its control
The triage's expression (
^\s*\}, ?[0-9_]+\);) still returns 2 against #13688's landedtarget file, so a zero elsewhere is a reading rather than a broken regex. Re-run structurally
(TypeScript AST, not grep) at
dda969cd71:sql-driver-diagnostic-value-probe.test.ts, 3 more in-cellunbudgeted blocks (40 in total, not 37). The card's instrument appears to have pre-filtered
to files with zero budget lines, and this file has one — on its
beforeAll. That file isthe only such leak in the package.
way. The card's scoping was right; only its instrument was slightly lossy.
A2.2 — are all 37 really full connect/DDL cycles? Checked one by one, not on faith
No. Of the 40 in-cell unbudgeted blocks, 35 construct a fresh
new SqlDriver(...)in theirown body and 5 do not (the table above). Every one of the 35 was inspected for its
constructor argument; three of them (
sql-driver-11389-date-tz-skew.test.ts:439,sql-driver-11565-row-byte-budget.test.ts:201,sql-driver-keyed-text-mysql.test.ts:285) dotheir DDL through
driver.execute('create table ...')or an internal probe rather thaninitObjects(...), but all three still open a fresh live connection per test, so they belongto the same class.
sql-driver-11565-row-byte-budget.test.ts:201is the cheapest of them — aconnect plus one metadata query, no DDL — and is included on the connect cost alone.
A2.3 — same-shaped live tests OUTSIDE
declareDialectCell: yes, 4. Reported, not folded inDiscriminated by reading each
new SqlDriver(ARG)argument rather than by guessing:live-dialect-matrix.isolation.test.ts:281it.skipIf(!PG_CELL.available)PG_CELL.config()live-dialect-matrix.isolation.test.ts:314it.skipIf(!PG_CELL.available)PG_CELL.config()sql-driver-autonumber-cold-race.test.ts:159it.skipIf(!pgCell.available)pgCell.config()sql-driver-json-binding-without-ddl.test.ts:173it{ ...PG_CELL.config(), schemaMode: 'validate-only' }The other 42 outside-cell driver-constructing
it()s are embedded SQLite(
dialectCell('sqlite').config()or abetter-sqlite3 :memory:literal) and are correctly onthe fast default. Per the dispatch order these 4 are reported, not folded into this PR;
filed with the
beforeAllgap as a separate finding.A2.4 — does a 60_000 budget turn a should-be-red test into a slowly-green one?
No — and this was checked with a firing positive control for every detector, so each zero
is a measurement rather than a broken expression.
Date.now/performance.now)elapsed, span compare)sql-driver-connect-bound.test.ts:196)sql-driver-server-timing.test.ts:68)*.test.ts; expression proved onlive-dialect-matrix.testkit.ts:190(for (;;))sql-driver-autonumber-tx.test.ts:94)Promise.all)Shanghai,change,unchanged)None of the 35 asserts on duration, sleeps, loops unboundedly, or contends for a lock. Each
asserts on
information_schemacontents, an error envelope, or row values — so the failuremode a real regression produces here is an assertion mismatch, which a larger budget does
not hide.
The honest cost, stated rather than buried: a future regression that manifests as unbounded
slowness would now take 60s to surface instead of 5s. That is the same cost #13688 accepted
for the same reason, and it is what the per-file disclaimer comment exists to keep visible.
Ablation
Two parts, because the literal one cannot reach the mechanism. No rebuild leg applies and
none was fabricated: the mutated subject is a test file vitest reads from disk, and these
files import the driver by relative specifier (
./sql-driver.js), never through the packageexportsmap, so nothing here is served fromdist/.Part 1 — literal, on the committed implementation. Predicted before running: no
change, because the edited blocks sit in unprovisioned cells. Removed all three budgets from
sql-driver-string-maxlength-varchar.test.ts; mutation confirmed on disk by blob hash(
646b0050a5...to9450642b90...) and by count (3 budgets to 0), never by the editor's exitcode. Both legs read identically:
Test Files 1 passed (1),Tests 4 passed | 2 skipped (6),with the two skips named:
That is the measurement establishing the vacuity of a local run over these blocks — it is
not evidence the budget does nothing. Restored with
git checkout HEAD -- ABSOLUTE_PATHunder a
trap ... EXIT INT TERM; restore proven by the blob returning to646b0050a5...andgit diff HEADbeing empty for the path.(A first attempt at Part 1 exited 1 in both legs with
No test files found— a repo-relativepath handed to a vitest whose cwd is the package. That is an invocation error, recorded as
such and re-run correctly; it is not reported as a red leg.)
Part 2 — mechanism probe, the leg that can run here. Predicted before running: without a
third argument the probe reds on 5000ms; with
, 60_000it goes green. A temporary probesleeping 6500ms, run under this package's real vitest config:
Both legs matched the prediction. This is what Part 1 cannot reach: that the inherited default
really is 5000ms in this package, and that the third argument this PR adds is honoured. The
probe was deleted afterwards and
git status --porcelainverified empty.Tests
All at HEAD
5abe7caa02, viascripts/pm/os-verify-lock.sh(shared-box seconds).pnpm --workspace-concurrency=2 --filter '@objectstack/driver-sql^...' build—
VERDICT command-exit 0.pnpm --filter @objectstack/driver-sql typecheck && pnpm --filter @objectstack/driver-sql exec vitest run --maxWorkers=2—
VERDICT command-exit 0(one&&chain, so the verdict certifies both).tsc --noEmit --listFilesnames all 8 ofthem (157
*.test.tsin the program), so this is not the "typecheck excludes tests" greenover source nothing read.
OS_TEST_MYSQL_URL,OS_TEST_POSTGRES_URLandOS_EXPECT_LIVE_DIALECT_MATRIXare all unset, sodeclareDialectCellcollapses each livecell to one named skip (quoted above). They run for real in
Temporal Conformance (live PG + MySQL).node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(change set read by thescript itself from merge base
dda969cd7: 8 paths, matching the diff): 22 path-matched plus 5convention-triggered ("adds or edits a test file"). 23 run, all exit 0, each captured
before any pipe. Their own verdict lines, not a bare
$?:check-cross-package-test-inputs:OK: 24 package(s) read outside themselves, all declaredcheck:where-matcher:323 matcher(s) discovered ... 0 silently-wrong ... baseline key set verified against dda969c: no files added(ratchet did not move)check-nul-bytes:OK (scanned 7702 text file(s) ... no raw ASCII control bytes)check-driver-conformance:OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exemptcheck:doc-authoring,check:logger-receiver-detach,check:objectql-double-limit,check:page-declaration-shape,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check:type-check-coverage,check:engine-double-contract,check-ci-filter-parity,check-comment-mask-adoption,check-keyed-text-bounds,check-plugin-teardown-shape,check-shard-attestation,check-undeclared-dep-imports,docs-audit/check-affected-docs,docs-audit/check-drift-comment.check:dual-build-cjs-loadsandcheck:type-check-debtneed the whole workspace built (CI's own Build Core scope, notwarranted locally for a test-only diff);
check:test-completenessexitsPREREQUISITE NOT METwithout a savedturbo run testlog, which CI tees and this branchcannot.
node --stack-size=4000 node_modules/eslint/bin/eslint.js . --no-inline-config—
VERDICT command-exit 0, zero output lines, 61s.No changeset
skip-changeset. The entire diff is eight test files — timeout budgets and explanatorycomments. No production code, no assertion and no control changed; nothing is published from
any package. Same disposition as PR #13908, whose diff was the same kind.
Generated by Claude Code